package com.taoz.mianshiwa.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.taoz.mianshiwa.common.BaseResponse;
import com.taoz.mianshiwa.common.DeleteRequest;
import com.taoz.mianshiwa.common.ErrorCode;
import com.taoz.mianshiwa.common.ResultUtils;
import com.taoz.mianshiwa.constant.UserConstant;
import com.taoz.mianshiwa.esdao.QuestionEsDao;
import com.taoz.mianshiwa.exception.BusinessException;
import com.taoz.mianshiwa.exception.ThrowUtils;
import com.taoz.mianshiwa.helper.CrawlerDetectHelper;
import com.taoz.mianshiwa.model.dto.question.*;
import com.taoz.mianshiwa.model.entity.Question;
import com.taoz.mianshiwa.model.entity.User;
import com.taoz.mianshiwa.model.vo.QuestionVO;
import com.taoz.mianshiwa.service.QuestionService;
import com.taoz.mianshiwa.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 题目接口
 */
@RestController
@RequestMapping("/question")
@Slf4j
public class QuestionController {

    @Resource
    private QuestionService questionService;
    @Resource
    private UserService userService;
    @Resource
    private CrawlerDetectHelper crawlerDetectHelper;
    @Resource
    private QuestionEsDao questionEsDao;

    @SaCheckRole(UserConstant.ADMIN_ROLE)
    @PostMapping("/delete/batch")
    public BaseResponse<Boolean> batchDeleteQuestions(@RequestBody QuestionBatchDeleteRequest questionBatchDeleteRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(questionBatchDeleteRequest == null, ErrorCode.PARAMS_ERROR);
        List<Long> questionIdList = questionBatchDeleteRequest.getQuestionIdList();
        ThrowUtils.throwIf(CollUtil.isEmpty(questionIdList), ErrorCode.PARAMS_ERROR);

        questionService.batchDeleteQuestions(questionIdList);
        questionEsDao.deleteAllById(questionIdList);

        return ResultUtils.success(true);
    }


    /**
     * 到ES中查询问题分页
     * @param questionQueryRequest
     * @return
     */
    @PostMapping("/search/page/vo")
    public BaseResponse<Page<QuestionVO>> searchQuestionVOByPage(@RequestBody QuestionQueryRequest questionQueryRequest) {
        // 限制爬虫
        ThrowUtils.throwIf(questionQueryRequest.getPageSize() > 20, ErrorCode.PARAMS_ERROR);

        Page<Question> questionPage;

        // 查询ES,如果查询ES失败就查询数据库进行接口降级
        try {
            questionPage = questionService.searchQuestionByPage(questionQueryRequest);
        } catch (Exception e) {
            questionPage = questionService.listQuestionByPage(questionQueryRequest);
        }

        // 获取封装类
        return ResultUtils.success(questionService.getQuestionVOPage(questionPage));
    }

    /**
     * 创建题目
     *
     * @param questionAddRequest
     * @return
     */
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    @PostMapping("/add")
    public BaseResponse<Long> addQuestion(@RequestBody QuestionAddRequest questionAddRequest) {
        // 参数校验 至少要有题目
        ThrowUtils.throwIf(StrUtil.isBlank(questionAddRequest.getTitle()), ErrorCode.PARAMS_ERROR);

        Question question = new Question();
        BeanUtils.copyProperties(questionAddRequest, question);
        question.setUserId(StpUtil.getLoginIdAsLong());
        List<String> tags = questionAddRequest.getTags();
        if (tags != null) {
            question.setTags(JSONUtil.toJsonStr(tags));
        }
        // 写入数据库
        boolean result = questionService.save(question);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        questionEsDao.save(QuestionEsDTO.objToDto(questionService.getById(question.getId())));

        return ResultUtils.success(question.getId());
    }

    /**
     * 删除题目
     *
     * @param deleteRequest
     * @return
     */
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteQuestion(@RequestBody DeleteRequest deleteRequest) {
        // 参数校验
        ThrowUtils.throwIf(deleteRequest.getId() == null, ErrorCode.PARAMS_ERROR);

        // 操作数据库
        boolean result = questionService.removeById(deleteRequest.getId());
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);

        // ES数据同步
        questionEsDao.deleteById(deleteRequest.getId());

        return ResultUtils.success(true);
    }

    /**
     * 更新题目（仅管理员可用）
     *
     * @param questionUpdateRequest
     * @return
     */
    @PostMapping("/update")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> updateQuestion(@RequestBody QuestionUpdateRequest questionUpdateRequest) {
        ThrowUtils.throwIf(questionUpdateRequest.getId() == null, ErrorCode.PARAMS_ERROR);

        Question question = new Question();
        BeanUtils.copyProperties(questionUpdateRequest, question);
        question.setTags(JSONUtil.toJsonStr(questionUpdateRequest.getTags()));
        // 操作数据库
        boolean result = questionService.updateById(question);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        // ES数据同步
        questionEsDao.save(QuestionEsDTO.objToDto(questionService.getById(question.getId())));

        return ResultUtils.success(true);
    }

    /**
     * 根据 id 获取题目（封装类）
     *
     * @param id
     * @return
     */
    @SaCheckLogin
    @GetMapping("/get/vo")
    public BaseResponse<QuestionVO> getQuestionVOById(Long id) {
        // 爬虫检测
        // 如果是爬虫应该抛异常直接退出
        crawlerDetectHelper.detectCrawlerByCount(StpUtil.getLoginIdAsLong());

        // 查询数据库
        Question question = questionService.getById(id);
        ThrowUtils.throwIf(question == null, ErrorCode.NOT_FOUND_ERROR);

        // 获取封装类
        return ResultUtils.success(questionService.getQuestionVO(question));
    }

    /**
     * 分页获取题目列表（仅管理员可用）
     *
     * @param questionQueryRequest
     * @return
     */
    @PostMapping("/list/page")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<Question>> listQuestionByPage(@RequestBody QuestionQueryRequest questionQueryRequest) {
        return ResultUtils.success(questionService.listQuestionByPage(questionQueryRequest));
    }

    /**
     * 分页获取题目列表（封装类）
     *
     * @param questionQueryRequest
     * @return
     */
    @PostMapping("/list/page/vo")
    public BaseResponse<Page<QuestionVO>> listQuestionVOByPage(@RequestBody QuestionQueryRequest questionQueryRequest) {
        // 限制爬虫
        ThrowUtils.throwIf(questionQueryRequest.getPageSize() > 20, ErrorCode.PARAMS_ERROR);

        // 查询数据库
        Page<Question> questionPage = questionService.listQuestionByPage(questionQueryRequest);

        // 获取封装类
        return ResultUtils.success(questionService.getQuestionVOPage(questionPage));
    }
}
